<!--
 * @Author: 姚杰鸿 adolphus520@163.com
 * @Date: 2025-07-31 16:49:41
 * @LastEditors: 姚杰鸿 adolphus520@163.com
 * @LastEditTime: 2025-08-05 15:41:04
 * @FilePath: /mds/src/components/other/MonacoEditor.vue
 * @Description: 请填写文件功能描述
 * @License: Copyright (c) 2025 by 姚杰鸿 email: adolphus520@163.com, All Rights Reserved. 
-->
<template>
  <div ref="editorContainer"></div>
</template>

<script lang="ts" setup>
import * as monaco from "monaco-editor"; // 全部导入
import { MenuRegistry, MenuId } from 'monaco-editor/esm/vs/platform/actions/common/actions.js';
import { ref, onMounted, toRaw, onUnmounted } from "vue";
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';

// 扩展描述符类型，支持嵌套子菜单
interface MenuDescriptor {
  title: string;
  context: string; // 唯一标识，用于创建MenuId
  group: string;
  order: number;
  // 动作可以是最终执行的动作，或包含子菜单的容器
  actions: (MenuAction | SubmenuDescriptor)[];
}

// 最终执行的动作（三级菜单）
interface MenuAction {
  id: string;
  label: string;
  run: () => void;
}

// 子菜单容器（二级菜单，可包含三级动作）
interface SubmenuDescriptor {
  type: 'submenu'; // 标记为子菜单容器
  title: string;
  context: string; // 二级菜单的唯一标识
  actions: MenuAction[]; // 三级动作
}

// 解决vite Monaco提示错误
self.MonacoEnvironment = {
    getWorker() {
        return new JsonWorker();
    },
};

const editor = ref(),
  props = defineProps({
    value: {
      type: String,
      default: "",
    },
    language: {
      type: String,
      default: "",
    },
  }),
  emit = defineEmits(["update:value", "contextmenu"]),
  editorContainer = ref();

onMounted(() => {
  editor.value = monaco.editor.create(editorContainer.value, {
    value: props.value || "",
    language: props.language || "json",
    minimap: {
      enabled: true,
    },
    colorDecorators: true,
    readOnly: false,
    theme: "vs-dark",
    automaticLayout: true,
    wordWrapColumn: 120,
    wordWrap: "on",
    tabSize: 8,
    insertSpaces: true,
    fixedOverflowWidgets: true,
    fontFamily: "Arial",
    fontSize: 18,
    autoClosingBrackets: "always",
    autoClosingOvertype: "always",
    autoClosingQuotes: "always",
  });
  // 监听编辑器内容变化
  editor.value.onDidChangeModelContent(() => {
    // 触发父组件的 change 事件，通知编辑器内容变化
    emit("update:value", toRaw(editor.value).getValue());
  });
  editor.value.addAction({
    id: "12345", // 菜单项 id
    label: "全屏", // 菜单项名称
    keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.F11], // 绑定快捷键
    contextMenuGroupId: "9_cutcopypaste", // 所属菜单的分组
    run: () => {
      emit("contextmenu", "fullscreen");
    }, // 点击后执行的操作
  });
  editor.value.addAction({
    id: "12346", // 菜单项 id
    label: "切换语言", // 菜单项名称
    contextMenuGroupId: "9_cutcopypaste", // 所属菜单的分组
    run: () => {
      monaco.editor.setModelLanguage(editor.value.getModel(), "typescript");
    }, // 点击后执行的操作
  });
  // 初始化自定义菜单
  //setupContextMenuFeature();
});

const setupContextMenuFeature = () => {
	//removeAllMenus();
	addActionWithSubmenus({
		title: 'MainRoot',
		context: 'EditorChangeRoot',
		group: 'edit',
		order: 0,
    actions: [
      // 二级菜单容器（包含三级动作）
      {
        type: 'submenu',
        title: 'Change color',
        context: 'EditorChangeColorContext',
        actions: [
          { id: 'red', label: 'Red', run: () => console.log('red') },
          { id: 'green', label: 'Green', run: () => console.log('green') }
        ]
      },
      // 二级菜单容器（包含三级动作）
      {
        type: 'submenu',
        title: 'Change coordinates',
        context: 'EditorChangeCoordinatesContext',
        actions: [
          { id: 'wgs', label: 'WGS', run: () => console.log('wgs') },
          { id: 'utc', label: 'UTC', run: () => console.log('utc') },
          { id: 'mgrs', label: 'MGRS', run: () => console.log('mgrs') }
        ]
      }
    ]
	});
};


// 改造后的添加菜单函数，支持三级结构
const addActionWithSubmenus = (descriptor: MenuDescriptor) => {
  // 1. 创建一级菜单的容器（如果有子菜单）
  const rootSubmenu = new MenuId(descriptor.context);
  const rootList: any[] = [];
  MenuRegistry._menuItems.set(rootSubmenu, rootList);

  // 2. 处理一级菜单下的动作（可能是二级容器或直接动作）
  descriptor.actions.forEach((item, index) => {
    if ((item as SubmenuDescriptor).type === 'submenu') {
      // 处理二级子菜单容器
      const submenuDesc = item as SubmenuDescriptor;
      const submenu = new MenuId(submenuDesc.context);
      const subList: any[] = [];
      MenuRegistry._menuItems.set(submenu, subList);

      // 3. 注册三级动作（二级容器下的具体动作）
      submenuDesc.actions.forEach((action, i) => {
        editor.value.addAction({
          id: action.id,
          label: action.label,
          run: action.run,
          contextMenuOrder: i,
          contextMenuGroupId: submenuDesc.context, // 绑定到二级容器的context
        });

        // 将三级动作从全局菜单移到二级容器中
        const actionId = editor.value.getSupportedActions()
          .find((a: any) => a.label === action.label && a.id.endsWith(action.id)).id;
        const items = MenuRegistry._menuItems.get(MenuId.EditorContext);
        const actionItem = popItem(items, actionId);
        if (actionItem) subList.push(actionItem);
      });

      // 4. 将二级容器添加到一级菜单中
      rootList.push({
        group: submenuDesc.context,
        order: index,
        submenu: submenu, // 关联二级容器的MenuId
        title: submenuDesc.title, // 二级菜单显示文本
      });
    } else {
      // 处理一级菜单下的直接动作（二级动作，非容器）
      const action = item as MenuAction;
      editor.value.addAction({
        id: action.id,
        label: action.label,
        run: action.run,
        contextMenuOrder: index,
        contextMenuGroupId: descriptor.context,
      });

      const actionId = editor.value.getSupportedActions()
        .find((a: any) => a.label === action.label && a.id.endsWith(action.id)).id;
      const items = MenuRegistry._menuItems.get(MenuId.EditorContext);
      const actionItem = popItem(items, actionId);
      if (actionItem) rootList.push(actionItem);
    }
  });

  // 5. 将一级菜单添加到右键菜单
  MenuRegistry._menuItems.get(MenuId.EditorContext).push({
    group: descriptor.group,
    order: descriptor.order,
    submenu: rootSubmenu, // 关联一级菜单的容器
    title: descriptor.title, // 一级菜单显示文本
  });
};

// 工具函数：从菜单列表中移除项（复用原有逻辑）
const popItem = (items: any, id: any) => {
  let node = items._first;
  do {
    if (node.element?.command?.id === id) {
      items._remove(node);
      return node.element;
    }
    node = node.next;
  } while (node !== undefined);
};

</script>
